<!DOCTYPE html>
<html lang="zh-CN">
  <head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="description" content="">
  <meta name="keywords" content="">
  
    <link rel="icon" href="/avatar.jpg">
  
    
  <title>使用 org 的文件名作为 EGO 生成的 URL | 科学君的不科学博客</title>
  <link rel="stylesheet" href="/style.css">
  <link rel="stylesheet" href="/lib/jquery.fancybox.min.css">
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
  <script type="text/javascript" src="https://tajs.qq.com/stats?sId=65546304" charset="UTF-8"></script>
  <script>
  (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      if (curProtocol === 'https') {
          bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
      }
      else {
          bp.src = 'http://push.zhanzhang.baidu.com/push.js';
      }
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
  })();
  </script>
</head>

<body>
  <header>
  <div class="header-container">
    <a class='logo' href="/">
      <span>科学君的不科学博客</span>
    </a>
    <ul class="right-header">
      
        <li class="nav-item">
          
            <a href="/" class="item-link">首页</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/about" class="item-link">关于</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/archives" class="item-link">归档</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/tags" class="item-link">标签</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/atom.xml" class="item-link">FEED 订阅</a>
          
        </li>
      
    </ul>
  </div>
</header>

  <main id='post'>
  <div class="content">
    <article>
      <section class="content markdown-body">
        <h1>使用 org 的文件名作为 EGO 生成的 URL</h1>
        <div class='post-meta'>
          <i class="fa fa-calendar" aria-hidden="true"></i>
          <time>2016年08月22日</time>
          
          | <i class="fa fa-folder-open-o" aria-hidden="true"></i> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/blog/">blog</a>
  </div>



          
          
          |
          
          <i class="fa fa-tags" aria-hidden="true"></i>
          
          
  <a href="/tags/#EGO" class='tag'>EGO</a>

  <a href="/tags/#emacs" class='tag'>emacs</a>


          
        </div>
        <ul>
<li><a href="#sec-">概述</a></li>
<li><a href="#sec-">改进方法</a></li>
<li><a href="#sec-">原理</a></li>
<li><a href="#sec-">16/8/23 更新</a></li>
<li><a href="#sec-">16/8/24 更新</a></li>
</ul>
<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述<a id="sec-"></a></h1><p>EOG 默认是使用文章的标题来生成 URL 的，这么做的坏处有二：</p>
<ol>
<li>如果文章的标题里面有汉字，生成的 URL 因为编码的原因会变的特别长，不美观。</li>
<li>只要更改了文章的标题，URL 就会随之而改变，以后就不好找了。而且 disqus 和多说也会把 修改标题之后的文章当成新的文章。</li>
</ol>
<p>我修改了 EGO 生成 URL 的策略，现在我的博客就是使用 hack 之后的 EGO 来生成的。</p>
<h1 id="改进方法"><a href="#改进方法" class="headerlink" title="改进方法"></a>改进方法<a id="sec-"></a></h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">(defun liu233w//ego--generate-uri (default-uri-template creation-date title)</span><br><span class="line">  &quot;类似于`ego--generate-uri&apos;，只不过读取 org 的文件名作为 title&quot;</span><br><span class="line">  (let ((uri-template (or (ego--read-org-option &quot;URI&quot;)</span><br><span class="line">                          default-uri-template))</span><br><span class="line">        (date-list (split-string (if creation-date</span><br><span class="line">                                     (ego--fix-timestamp-string creation-date)</span><br><span class="line">                                   (format-time-string &quot;%Y-%m-%d&quot;))</span><br><span class="line">                                 &quot;-&quot;))</span><br><span class="line">        (encoded-title (ego--encode-string-to-url</span><br><span class="line">                        ;; 获取 buffer 的文件名</span><br><span class="line">                        (replace-regexp-in-string &quot;^.*/\\|\\.org$&quot; &quot;&quot; (buffer-file-name)))))</span><br><span class="line">    (format-spec uri-template `((?y . ,(car date-list))</span><br><span class="line">                                (?m . ,(cadr date-list))</span><br><span class="line">                                (?d . ,(cl-caddr date-list))</span><br><span class="line">                                (?t . ,encoded-title)))))</span><br></pre></td></tr></table></figure>
<p>如果你不介意直接覆盖函数的话，可以把函数名换成 <code>ego--generate-uri</code> ，这样 EGO 的默认函数就 被覆盖了。如果你不想这么做，可以修改 <code>ego--category-config-alist</code> 中的 <code>:uri-generator</code> ， 如我的代码所示：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">(setf ego--category-config-alist</span><br><span class="line">            &apos;((&quot;blog&quot;</span><br><span class="line">               :show-meta t</span><br><span class="line">               :show-comment t</span><br><span class="line">               ;; 将 org 的文件名当做 uri，参考函数</span><br><span class="line">               :uri-generator liu233w//ego--generate-uri</span><br><span class="line">               :uri-template &quot;/blog/%y/%m/%d/%t/&quot;</span><br><span class="line">               :sort-by :date     ;; how to sort the posts</span><br><span class="line">               :category-index t) ;; generate category index or not</span><br><span class="line">              (&quot;acm&quot;</span><br><span class="line">               :show-meta t</span><br><span class="line">               :show-comment t</span><br><span class="line">               ;; 将 org 的文件名当做 uri，参考函数</span><br><span class="line">               :uri-generator liu233w//ego--generate-uri</span><br><span class="line">               :uri-template &quot;/acm/%y/%m/%d/%t/&quot;</span><br><span class="line">               :sort-by :date     ;; how to sort the posts</span><br><span class="line">               :category-index t)</span><br><span class="line">              (&quot;index&quot;</span><br><span class="line">               :show-meta nil</span><br><span class="line">               :show-comment nil</span><br><span class="line">               :uri-generator ego--generate-uri</span><br><span class="line">               :uri-template &quot;/&quot;</span><br><span class="line">               :sort-by :date</span><br><span class="line">               :category-index nil)</span><br><span class="line">              (&quot;about&quot;</span><br><span class="line">               :show-meta nil</span><br><span class="line">               :show-comment nil</span><br><span class="line">               :uri-generator ego--generate-uri</span><br><span class="line">               :uri-template &quot;/about/&quot;</span><br><span class="line">               :sort-by :date</span><br><span class="line">               :category-index nil)</span><br><span class="line">              ))</span><br></pre></td></tr></table></figure>
<h1 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理<a id="sec-"></a></h1><p>相比于原来的函数，我只是把 let 中的参数 <code>title</code> 换成了 <code>(replace-regexp-in-string &quot;^.*/\\|\\.org$&quot; &quot;&quot; (buffer-file-name))</code> 而已。因为这个函数会在每一个打开的 buffer 中运行，所以可以通过 <code>buffer-file-name</code> 来获取当前 org 文件的路径，然后用正则表达式把多余的内容删掉，只保留文件名即可。</p>
<p>表达式的效果：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(replace-regexp-in-string &quot;^.*/\\|\\.org$&quot; &quot;&quot;</span><br><span class="line">                          &quot;d:/TOTALCMD/tools/emacs/home/documents/blog/blog/change-url-generator.org&quot;)</span><br></pre></td></tr></table></figure>
<pre><code>change-url-generator
</code></pre><p>比较神奇的是 emacs 的正则表达式居然是把转义之后的 <code>|</code> 符号当做分支符号，而没有转义的 是符号本身，这跟其他的正则表达式实现不一样啊。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(replace-regexp-in-string &quot;ab|c&quot; &quot;dd&quot; &quot;ab|c&quot;)</span><br></pre></td></tr></table></figure>
<pre><code>dd
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(replace-regexp-in-string &quot;ab\\|c&quot; &quot;dd&quot; &quot;ab|c&quot;)</span><br></pre></td></tr></table></figure>
<pre><code>dd|dd
</code></pre><p>貌似括号也是这样的。</p>
<h1 id="16-8-23-更新"><a href="#16-8-23-更新" class="headerlink" title="16/8/23 更新"></a>16/8/23 更新<a id="sec-"></a></h1><p>作者根据<a href="https://github.com/emacs-china/EGO/issues/85" target="_blank" rel="noopener">我的 issue</a> 修改了这个函数，现在 EGO 可以在 URL 里面添加一个 <code>%f</code> 的模板来表示文件名 了。也就是说可以把 URL 改成 <code>/blog/%y/%m/%d/%f/</code> 来在生成的时候使用文件名作为 URI。但是由于 每一篇文章里面都有元数据的 URL，我就必须修改每一篇文章了。而且文章的模板没有相应的做出改变， <code>ego--insert-options-template</code> 和 <code>ego-new-post</code> 也没有改，目前使用这种方法还比较麻烦。 我暂时还不会修改自己的配置，等到这两个函数完善之后再说吧。</p>
<h1 id="16-8-24-更新"><a href="#16-8-24-更新" class="headerlink" title="16/8/24 更新"></a>16/8/24 更新<a id="sec-"></a></h1><p>找到了新的办法：用 nadvice.el 修改 <code>ego--insert-options-template</code> 即可。请确保以下的 代码在 EGO 加载之后运行。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">(require &apos;nadvice)</span><br><span class="line">;; 改变默认的元数据模板，使插入的 URL 为 &quot;category/%y/%m/%d/%f/&quot;</span><br><span class="line">(defun org-config//advice-of-ego--insert-options-template (args)</span><br><span class="line">  (setf (second args)</span><br><span class="line">        (replace-regexp-in-string &quot;%t/ Or .*$&quot; &quot;%f/&quot;</span><br><span class="line">                                  (second args)))</span><br><span class="line">  args)</span><br><span class="line"></span><br><span class="line">(advice-add &apos;ego--insert-options-template :filter-args</span><br><span class="line">            &apos;org-config//advice-of-ego--insert-options-template</span><br><span class="line">            )</span><br></pre></td></tr></table></figure>
<p><code>nadvice.el</code> 是一个 emacs 内置的新 package，与 defadvice 类似，它可以改变 某个函数的默认行为。 <code>ego-new-post</code> 会调用 <code>ego--insert-options-template</code> 来插入 org 文件的元数据。 <code>advice-added</code> 函数通过参数 <code>:filter-args</code> 将我的自定义函数 套在了原来函数的外面，传递给原函数的参数要经过我的函数的处理才能真正传递给它。</p>
<p>如果你在新建文章的时候使用了默认生成的模板（调用 <code>ego-new-post</code> 函数的最后回答 yes）， 传递给 <code>ego--insert-options-template</code> 的第二个参数（URL 模板）默认会是 <code>/your-category/%y/%m/%d/%t/ Or /your-category/%t/</code> ，我的函数将通过正则表达式把它 替换成 <code>/your-category/%y/%m/%d/%f/</code> ，默认使用文件名当做 URL，这样就不需要再手动修改了。 如果你回答 no 来自己指定标题和 uri 的话，我的函数是不会影响的。</p>
<p>现在就可以去掉原来自定义的 <code>ego--generate-uri</code> 函数，把原来 org 文件里面的 <code>%t</code> 替换成 <code>%f</code> 了。上面的代码可比原来的修改少多了。</p>
<p>至于批量替换，可以用 emacs 的 dired 来做。用 dired 标记所有需要替换的文件，然后按 <code>Q</code> ， 就可以像在一个文件中替换文本那样替换所有文件中的文本了。</p>

      </section>
      <div class="license">
        <a href="http://creativecommons.org/licenses/by-sa/3.0/" rel="license" target="_blank">
          <img src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" style="border-width:0"
               alt="Creative Commons License" class="center">
        </a>
      </div>
      <p>
        本作品采用
        <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" target="_blank">
          署名-相同方式共享 4.0 国际
        </a>
        进行许可。欢迎转载、使用、重新发布，但务必保留文章署名
        “不科学的科学君” (Liu233w) 与博客链接：
        <a href="https://liu233w.github.io">https://liu233w.github.io</a>
        ，基于本文修改后的作品务必以相同的许可发布。如有任何疑问，请
        <a href="mailto:wwwlsmcom@outlook.com" target="_blank">与我联系</a>
        。
      </p>
    </article>
    
    <!-- disqus 评论框 start -->
    <div class="comment">
      <div id="disqus_thread" class="disqus-thread">
        <i>加载评论框需要翻墙</i>
      </div>
    </div>
    <!-- disqus 评论框 end -->
    
    
    <!-- livere 评论框 start -->
    <div class="comment">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zNTE5NS8xMTczMA=="></div>
    </div>
    <!-- livere 评论框 end -->
    
  </div>
  <aside>
    
    <div class="toc-container">
      <h1>目录</h1>
      <div class="content">
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#概述"><span class="toc-number">1.</span> <span class="toc-text">概述</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#改进方法"><span class="toc-number">2.</span> <span class="toc-text">改进方法</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#原理"><span class="toc-number">3.</span> <span class="toc-text">原理</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#16-8-23-更新"><span class="toc-number">4.</span> <span class="toc-text">16/8/23 更新</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#16-8-24-更新"><span class="toc-number">5.</span> <span class="toc-text">16/8/24 更新</span></a></li></ol>
      </div>
    </div>
    
  </aside>
</main>

<!-- disqus 公共JS代码 -->
<script type="text/javascript">
  /* * * CONFIGURATION VARIABLES * * */
  var disqus_shortname = "liu233w";
  var disqus_identifier = "https://liu233w.github.io/2016/08/22/change-url-generator.org/";
  var disqus_url = "https://liu233w.github.io/2016/08/22/change-url-generator.org/";

  isAgent(getDisqus)

  // determine user agent in China
  function isAgent(cb) {
    var url = '//graph.facebook.com/feed?callback=h';
    var xhr = new XMLHttpRequest();
    var called = false;
    xhr.open('GET', url);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        called = true;
        cb(true);
      }
    };
    xhr.send();
    // timeout 1s, this facebook API is very fast.
    setTimeout(function () {
      if (!called) {
        xhr.abort();
        cb(false)
      }
    }, 1000);
  }

  function getDisqus(isAgent) {
    var dsq = document.createElement('script');
    dsq.type = 'text/javascript';
    dsq.async = true
    dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq)
  }
</script>
<!-- disqus 公共JS代码 end -->


<script type="text/javascript">
  (function (d, s) {
    var j, e = d.getElementsByTagName(s)[0];

    if (typeof LivereTower === 'function') {
      return;
    }

    j = d.createElement(s);
    j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
    j.async = true;

    e.parentNode.insertBefore(j, e);
  })(document, 'script');
</script>


  <footer>
  <div class="copyright">
    <div>
      &copy; 2019 | Powered by <a href="https://hexo.io" target="_blank">Hexo</a>&nbsp
    </div>
    <div>
      Theme by <a href="https://github.com/lewis-geek/hexo-theme-Aath" target="_blank">Aath</a>
    </div>
  </div>
</footer>


<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="/lib/in-view.min.js"></script>
<script src="/lib/lodash.min.js"></script>
<script>
  var isDown = true
  var oldY = 0
  inView.offset(50)

  document.body.addEventListener('touchstart', function(){});
  
  window.addEventListener('scroll', _.throttle(e => {
    var currentY = window.scrollY
    if((oldY - currentY) < 0) {
      isDown = true
    } else {
      isDown = false
    }
    oldY = currentY
  }, 250))

  $("article img").each(function() {
      var strA = "<a data-fancybox='gallery' href='" + this.src + "'></a>";
      $(this).wrapAll(strA);
  });

  $('.toc-link').each(function() {
      var href = $(this).attr("href");
      
      inView(href).on('exit', () => {
        if (isDown) {
          handleActive(href)
        }
      })

      inView(href).on('enter', () => {
        if (!isDown) {
          handleActive(href)
        }
      })

      this.onclick = function(e) {
        var pos = $(href).offset().top - 10;
        $("html,body").animate({scrollTop: pos}, 300);
        setTimeout(() => {
          handleActive(href)
        }, 350)
        return false
      }
  })

  function handleActive(href) {
    document.querySelectorAll('.toc-link').forEach(elm => {
      elm.classList.remove('active')
    })
    document.querySelector(".toc [href='"+ href +"']").classList.add('active')
  }
</script>
<script src="/lib/jquery.fancybox.min.js"></script>

<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

</body>
</html>
